#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <errno.h>
#include <pthread.h>
#include <time.h>

#define SRV_PORT 8989
#define MAX_RECV_NUM 1024

struct sockaddr_in addrInfo;

void PrintTmst(void)
{
    char str[128] = {0};
    time_t tmst = time(NULL);
    struct tm *tmp = localtime(&tmst);
    (void)strftime(str, sizeof(str), "%F %a %T", tmp);
    fprintf(stderr, "\n%s", str);
}

void *SendThread(void *arg)
{
    if (arg == NULL) {
        fprintf(stderr, "check arg failed\n");
        exit(-1);
    }
    int fd = *(int *)arg;
    fprintf(stderr, "******************* start send *******************\n");
    while (1) {
        char buf[MAX_RECV_NUM] = {0};
        if (scanf("%s", buf) != EOF) {
            int len = sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&addrInfo, sizeof(addrInfo));
            if (len < 0 || (uint32_t)len != strlen(buf)) {
                fprintf(stderr, "send str failed: %s\n", buf);
            } else {
                fprintf(stderr, "send str successfully: %s\n", buf);
            }
        }
    }
}

int StartupSend(int *fd)
{
    pthread_attr_t threadAttr;
    pthread_t threadId;

    pthread_attr_init(&threadAttr);
    pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
    int rc = pthread_create(&threadId, &threadAttr, SendThread, fd);
    pthread_attr_destroy(&threadAttr);
    if (rc != 0) {
        fprintf(stderr, "pthread_create failed: %s\n", strerror(errno));
        return -1;
    }
    return 0;
}

int main(void)
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        fprintf(stderr, "create socket failed: %s\n", strerror(errno));
        return -1;
    }

    struct sockaddr_in srvInfo;
    bzero(&srvInfo, sizeof(srvInfo));
    srvInfo.sin_family = AF_INET;
    srvInfo.sin_port = htons(SRV_PORT);
    srvInfo.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(fd, (struct sockaddr *)&srvInfo, sizeof(srvInfo)) == -1) {
        fprintf(stderr, "bind failed: %s\n", strerror(errno));
        return -1;
    }

    bool sendFlag = false;
    while (1) {
        struct timeval timeout = {1, 0};
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        int maxfd = fd;
        int ret = select(maxfd + 1, &fds, NULL, NULL, &timeout);
        if (ret < 0) {
            fprintf(stderr, "select failed: %s\n", strerror(errno));
            return -1;
        } else if (ret == 0) { /* 超时 */
            continue;
        }

        if (FD_ISSET(fd, &fds)) {
            char buf[MAX_RECV_NUM] = {0};
            struct sockaddr_in cliInfo;
            bzero(&cliInfo, sizeof(cliInfo));
            socklen_t addrlen = sizeof(cliInfo);
            int num = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&cliInfo, &addrlen);
            if (num <= 0) {
                continue;
            }

            PrintTmst();
            fprintf(stderr, "\nrecv hex: ");
            for (int i = 0; i < num ; i++) {
                fprintf(stderr, "%02X", buf[i]);
            }
            fprintf(stderr, "\nrecv str: %s\n", buf);

            if (sendFlag) {
                continue;
            }
            addrInfo = cliInfo;
            if (StartupSend(&fd) == 0) {
                sendFlag = true;
            }
        }
    }
    return 0;
}